package org.zjx.window;

import org.zjx.log.LogLevel;
import org.zjx.log.Logger;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;


public class GlobalLockWithTimeout {
    private static final Logger logger = Logger.getLogger();
    // 使用ReentrantLock作为基础锁
    private static final ReentrantLock lock = new ReentrantLock();

    // 默认锁超时时间（毫秒）
    private static final long DEFAULT_LOCK_TIMEOUT = 10000; // 10秒

    // 锁状态
    private static volatile boolean isLocked = false;
    // 锁持有者线程
    private static Thread lockOwner = null;
    // 锁获取时间
    private static long lockAcquireTime = 0;
    // 锁超时时间
    private static long lockTimeout = DEFAULT_LOCK_TIMEOUT;

    /**
     * 尝试获取锁（使用默认超时时间）
     * @return 是否成功获取锁
     */
    public static boolean tryLock() {
        return tryLock(DEFAULT_LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
    }

    /**
     * 尝试获取锁（带自定义超时）
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return 是否成功获取锁
     */
    public static synchronized boolean tryLock(long timeout, TimeUnit unit) {
        // 检查锁是否已超时
        checkLockTimeout();

        try {
            // 尝试获取锁
            boolean acquired = lock.tryLock(timeout, unit);
            if (acquired) {
                // 锁成功获取
                isLocked = true;
                lockOwner = Thread.currentThread();
                lockAcquireTime = System.currentTimeMillis();
                lockTimeout = unit.toMillis(timeout);
//                logger.log("GameModule", LogLevel.INFO,"锁已成功获取，线程：" + lockOwner.getName());
            }
            return acquired;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 释放锁
     */
    public static synchronized void unlock() {
        if (lock.isHeldByCurrentThread()) {
            isLocked = false;
            lockOwner = null;
            lockAcquireTime = 0;
            lock.unlock();
//            logger.log("GameModule", LogLevel.INFO,"锁已释放，线程：" + Thread.currentThread().getName());
        } else {
            logger.log("GameModule", LogLevel.INFO,"当前线程不是锁的持有者，无法释放锁！");
        }
    }

    /**
     * 检查锁是否已超时，如果超时则自动释放
     */
    private static synchronized void checkLockTimeout() {
        if (isLocked && lockOwner != null && lockAcquireTime > 0) {
            long currentTime = System.currentTimeMillis();
            if (currentTime - lockAcquireTime > lockTimeout) {
                // 锁已超时，但只能由持有者线程释放
                if (lock.isHeldByCurrentThread()) {
                    unlock(); // 正常释放
                    logger.log("GameModule", LogLevel.INFO, "锁因超时被持有者线程释放"+ Thread.currentThread().getName());
                } else {
                    logger.log("GameModule", LogLevel.WARN, "锁已超时，但当前线程非持有者，无法释放"+ Thread.currentThread().getName());
                }
            }
        }
    }

    /**
     * 强制释放锁（即使不是锁持有者调用）
     */
    public static synchronized void forceUnlock() {
        if (isLocked && lockOwner != null) {
            // 只有锁持有者线程才能释放锁
            if (lock.isHeldByCurrentThread()) {
                isLocked = false;
                lockOwner = null;
                lockAcquireTime = 0;
                lock.unlock();
                logger.log("GameModule", LogLevel.INFO, "锁被持有者线程释放"+ Thread.currentThread().getName());
            } else {
                logger.log("GameModule", LogLevel.WARN, "当前线程不是锁持有者，无法强制释放锁"+ Thread.currentThread().getName());
            }
        }
    }

    /**
     * 获取锁状态
     * @return 是否被锁定
     */
    public static synchronized boolean isLocked() {
        checkLockTimeout(); // 检查超时
        return isLocked;
    }

    /**
     * 获取锁剩余时间（毫秒）
     * @return 剩余时间，如果未锁定返回0
     */
    public static synchronized long getRemainingTime() {
        if (!isLocked || lockAcquireTime == 0) {
            return 0;
        }
        long elapsed = System.currentTimeMillis() - lockAcquireTime;
        return Math.max(0, lockTimeout - elapsed);
    }

    public static void main(String[] args) {
        GlobalLockWithTimeout lock = new GlobalLockWithTimeout();

        // 测试锁获取与超时逻辑
        new Thread(() -> {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                try {
                    logger.log("GameModule", LogLevel.INFO,"线程1执行中...");
                    Thread.sleep(2000); // 模拟任务执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();

        new Thread(() -> {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                try {
                    logger.log("GameModule", LogLevel.INFO,"线程2执行中...");
                    Thread.sleep(2000); // 模拟任务执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();
    }
}
